← 返回文章列表

Dify MCP 集成实验(01):环境地基与首个 MCP Server——MCP 新版 SDK 如何从零跑通?

1. 业务场景

先讲一个我们实际遇到的场景。

一家做客服工单 SaaS 的公司,交付一个「企业级 AI 智能体系统集成」项目:外部系统数据要通过 MCP 进 Dify。交付工程师开工后的第一件事不是写业务逻辑,而是把开发环境搭起来、跑通第一个 server——就像盖楼先打地基。第一个工具选什么?一个「当前时间」工具:记录工单创建时间戳、排障时取基准时间、看板定时任务的调度基准。它无外部依赖、参数少、结果确定,是最简单的真实工具,适合当第一个 server 练手。

我们第一次接这类需求时,第一反应是「装个 SDK 写个 server 能有多难」。真正动手才发现——第一个坑不在业务,在地基:SDK 2.0 把旧 API 整个换掉、Python 3.14 装不上 wheel、Dify 只消费远程 HTTP 端点根本不走 stdio——环境没搭对,后面 02-06 的实验全部白搭。这个实验就是先把地基打牢。

这不是个例。任何「外部系统数据要进 Dify」的集成都是这个模式:Dify 只消费远程 HTTP/SSE 端点(源码确认:无 stdio)——server 必须能部署成可访问的 HTTP 端点,后续 02-06 实验的「Dify 连接」假设才成立。

2. 场景痛点

这个流程的痛点,在起步阶段体现得最直接:

本质上,环境地基决定了后面 02-06 全部实验能不能跑——地基没打牢,上层全悬空

3. 方案:为什么是 MCP 官方 SDK + Streamable HTTP

打通 MCP Server 开发环境地基,最直接的路就是官方 SDK 2.0 + Streamable HTTP 部署。

选它的理由:

这篇文章我们就用它搭第一个 MCP Server——「当前时间」工具,走完 SDK 安装 → server 结构 → 工具定义 → stdio 本地验证 → Streamable HTTP 部署的全生命周期。

4. 整体架构

graph TD dev["本地开发机:Python 3.11 venv + mcp 2.0.0(uv 管理)"] server["dify107_01_time_server"] stdio["stdio 模式(本地客户端验证)"] http["Streamable HTTP 端点(uvicorn :8901/mcp)"] dify["Dify 服务器(Docker Compose)"] api["api(FastAPI)"] web["web(控制台:工具页 MCP tab)"] proxy["107-03 实测:经 SSRF 代理接入"] dev --> server server --> stdio server --> http http -- "HTTP" --> dify dify --> api dify --> web api --> proxy

链路很清晰:本地开发机(Python venv + server)→ Streamable HTTP 端点 → Dify 服务器(api/web)。关键设计是 stdio 模式先本地验证工具逻辑,再以 streamable-http 部署成 Dify 可访问的端点——先证明工具对,再证明能连。

5. 模块设计

5.1 环境三件套(本实验核心)

# 1. 建 venv(一次):Python 3.11(3.14 装 mcp 有 wheel 兼容风险,106 教训延续)

cd dify-107/tmp && uv venv --python 3.11 venv311

# 2. 装 SDK:官方 mcp 2.0.0(自动带 uvicorn/starlette/anyio)

uv pip install --python venv311 mcp

# 3. 启动 Streamable HTTP 部署(Dify 接入形态)

venv311/Scripts/python server.py http   # → http://0.0.0.0:8901/mcp

5.2 Server 骨架与工具定义(SDK 2.0 新 API)

from mcp.server.mcpserver import MCPServer

server = MCPServer(

    name="dify107_01_time_server",

    version="1.0.0",

    description="客服工单 SaaS 时间基准工具",

)

@server.tool()

def get_current_time(timezone: str = "local") -> dict:

    """返回当前时间、时区与 UTC 偏移(可选参数 timezone)"""

    ...

# 三传输:stdio(开发验证)/ streamable-http(部署形态)/ sse

if __name__ == "__main__":

    server.run(transport="stdio" if sys.argv[1:] == ["stdio"]

               else "streamable-http", host="0.0.0.0", port=8901)

注意mcp 2.0.0 是 2026 新版,API 大改——mcp.server.fastmcp 模块不存在,旧教程里的 FastMCP 写法全部过时;新 API 在 mcp.server.mcpserver(MCPServer 类 + @server.tool() 装饰器 + run(transport=...))。

6. 运行验证

输入 预期 结果
stdio 调用(UTC+8) 2026-08-05 20:43:53,offset=+8h 通过
stdio 调用(UTC-5) 2026-08-05 07:43:53,offset=-5h(时差正确) 通过
stdio 调用(UTC+12) 次日 00:43:53 通过
HTTP 端点 tools/list 返回 get_current_time 工具 通过
HTTP 调用(local 默认) 本地时区 +8h 正确 通过
错误路径(无效参数) isError=True + 中文错误信息透传 通过

7. 实战坑

现象 修复
mcp 2.0.0 API 大改 mcp.server.fastmcp 模块不存在,旧教程 FastMCP 写法全报错 新 API:MCPServer + @server.tool() + run(transport=...)(实测)
Python 3.14 不兼容 3.14 装 mcp 有 wheel 风险(106 教训延续) uv venv --python 3.11 + uv pip install mcp(实测)
list_tools 返回结构 返回的不是 list 也不是元组,是 ListToolsResult 对象 访问 listing.tools;分页字段驼峰 nextCursor(实测)
pydantic 字段别名 协议 JSON 字段驼峰 isError,写 res.isError 报 AttributeError Python 属性访问用 snake_case:res.is_error(实测)
工具错误返回 server 内 raise ValueError 客户端收到 isError=True + "Error executing tool xxx: 信息"(错误信息透传)(实测)
默认端点路径 run(transport="streamable-http") 默认端点 /mcp streamable_http_path 参数可改(实测)
Windows 路径 MSYS /d/ 路径在 Windows 程序里报错 一律 D:\ 格式(106 教训延续)

8. 实验文档及源码获取

文章聚焦核心配置与采坑点;实验的完整分步操作(节点搭建/参数表/调试指引)见实验文档原文。

联系我

15088711270

手机端点击号码可直接拨打 · 桌面端可复制

微信二维码

扫码加微信 · 备注「门户」更快通过